Перейти к основному содержимому

5.03. Исключения

Разработчику Архитектору

Исключения

Исключения – это события, которые нарушают нормальное выполнение программы. Она может внезапно прекратить работу из-за ошибок в коде, некорректного ввода данных, сбоя в системе и т.д.

Все исключения в Java – это объекты, которые происходят от класса Throwable.

Throwable включает в себя Error и Exception.

Exception включает в себя RuntimeException (unchecked) и checked exceptions.

ТипПримерыОбязательная обработка
ErrorOutOfMemoryError, StackOverflowErrorНет
Checked ExceptionsIOException, SQLExceptionДа
Unchecked Exceptions (RuntimeException)NullPointerException, ArrayIndexOutOfBoundsExceptionНет

Error – серьёзные проблемы, не подлежащие обработке приложением. К примеру, сбой JVM. Эти ошибки не нужно и не рекомендуется перехватывать. Checked Exceptions – проверяемые исключения, которые компилятор требует обработать явно - либо через try-catch, либо через throws, к примеру FileNotFoundException (файл не найден), SQLException (ошибка SQL).

Пример:

public void readFile() throws IOException {
FileReader reader = new FileReader("file.txt");
}

Если метод может выбросить проверяемое исключение, его нужно объявить с ключевым словом throws или обработать внутри метода.

Unchecked Exceptions – непроверяемые исключения, которые являются производными от RuntimeException – компилятор их не проверяет, поэтому можно не обрабатывать – NullPointerException, ArithmeticException, ArrayIndexOutOfBoundsException. Пример:

int result = 10 / 0; // выбросит ArithmeticException

Эти исключения обычно сигнализируют о логических ошибках в коде, и их лучше предотвращать, чем обрабатывать.

Способы для обработки исключений:

  1. try-catch-finally – блок для перехвата и обработки исключения, по логике «попробуй так, и если поймаешь это, то делай так, и в итоге делай всегда ещё вот так»:
try {
int[] arr = new int[5];
System.out.println(arr[10]); // ArrayIndexOutOfBoundsException
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Ошибка: выход за границы массива");
} finally {
System.out.println("Этот блок выполнится всегда");
}

finally используется для освобождения ресурсов, например, закрытие файла или соединения.

  1. try-with-resources – автоматически закрывает ресурсы, реализующие интерфейс AutoCloseable:
try (FileReader reader = new FileReader("file.txt")) {
int data = reader.read();
} catch (IOException e) {
e.printStackTrace();
}
  1. throws указывает, что метод может выбросить исключение, и ответственность за его обработку передаётся вызывающему коду:
public void readData() throws IOException {
FileReader reader = new FileReader("data.txt");
}

Вызывающий код либо сам обрабатывает исключение:

try {
readData();
} catch (IOException e) {
e.printStackTrace();
}

Либо пробрасывает дальше:

public static void main(String[] args) throws IOException {
readData(); // опасно!
}

Чем выше поднимается исключение, тем сложнее обрабатывать. Лучше обрабатывать ближе к источнику ошибки - работа с ошибками - огромная часть функций разработчиков.

Можно использовать инструменты Java и создавать свои классы исключений, расширяя Exception или RuntimeException:

public class InvalidAgeException extends Exception {
public InvalidAgeException(String message) {
super(message);
}
}
// или

public class ValidationException extends RuntimeException {
public ValidationException(String message) {
super(message);
}
}

Использование:

public void checkAge(int age) throws InvalidAgeException {
if (age < 0) {
throw new InvalidAgeException("Возраст не может быть отрицательным");
}
}